﻿using System.Windows.Media;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using KinonekoSoftware.Foundation;
using KinonekoSoftware.Foundation.Styles;
using KinonekoSoftware.Foundation.UI.Media;

namespace KinonekoSoftware.Studio.Styles.Progress
{
    public class DegreePresenter : WrapPanel
    {

        public static readonly DependencyProperty BrushProperty;
        public static readonly DependencyProperty CornerRadiusProperty;
        public static readonly DependencyProperty MaximumProperty;
        public static readonly DependencyProperty IsLinearModeProperty;
        public static readonly DependencyProperty ThumbGapProperty;
        public static readonly DependencyProperty ThumbHeightProperty;
        public static readonly DependencyProperty ThumbWidthProperty;
        public static readonly DependencyProperty ValueProperty;

        static DegreePresenter()
        {
            CornerRadiusProperty = DependencyProperty.Register(nameof(CornerRadius),
                                                               typeof(CornerRadius),
                                                               typeof(DegreePresenter),
                                                               new PropertyMetadata(default(CornerRadius), OnCornerRadiusChanged));
            
            ThumbGapProperty = DependencyProperty.Register(nameof(ThumbGap),
                                                           typeof(int),
                                                           typeof(DegreePresenter),
                                                           new PropertyMetadata(8, OnVisualChanged));

            ThumbHeightProperty = DependencyProperty.Register(nameof(ThumbHeight),
                                                              typeof(int),
                                                              typeof(DegreePresenter),
                                                              new PropertyMetadata(10, OnVisualChanged));
            
            ThumbWidthProperty = DependencyProperty.Register(nameof(ThumbWidth),
                                                             typeof(int),
                                                             typeof(DegreePresenter),
                                                             new PropertyMetadata(8, OnVisualChanged));

            MaximumProperty = DependencyProperty.Register(nameof(Maximum),
                                                          typeof(int),
                                                          typeof(DegreePresenter),
                                                          new PropertyMetadata(10, OnMaximumChanged));

            
            ValueProperty = DependencyProperty.Register(nameof(Value),
                                                        typeof(int),
                                                        typeof(DegreePresenter),
                                                        new PropertyMetadata(0, OnValueChanged));

            IsLinearModeProperty = DependencyProperty.Register(nameof(IsLinearMode),
                                                               typeof(bool),
                                                               typeof(DegreePresenter),
                                                               new PropertyMetadata(Boxing.False, OnIsLinearModeChanged));
            
            BrushProperty = DependencyProperty.Register(nameof(Brush),
                                                        typeof(Brush),
                                                        typeof(DegreePresenter),
                                                        new PropertyMetadata(default(Brush), OnBrushChanged));
        }

        public DegreePresenter()
        {
            Loaded += OnLoaded;
            Unloaded += OnUnloaded;
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            //
            // 清空所有元素
            foreach (Border item in Children)
            {
                //
                // 移除事件
                item.MouseLeftButtonDown -= OnThumbMouseLeftButtonDown;
            }

            Children.Clear();
            GenerateElement(Maximum);
            OnValueChanged(Value);
        }

        private void OnUnloaded(object sender, RoutedEventArgs e)
        {
            Unloaded -= OnUnloaded;
            
            //
            // 清空所有元素
            foreach (Border item in Children)
            {
                //
                // 移除事件
                item.MouseLeftButtonDown -= OnThumbMouseLeftButtonDown;
            }
            Children.Clear();
        }

        private static void OnVisualChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = (DegreePresenter)d;
            var width  = sender.ThumbWidth;
            var margin = new Thickness(sender.ThumbGap / 2d);
            var height = sender.ThumbHeight;
            
            //
            // 设置所有元素
            foreach (Border item in sender.Children)
            {
                item.Margin = margin;
                item.Width  = width;
                item.Height = height;
            }
        }
        
        private static void OnBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = (DegreePresenter)d;
            
            //
            // 
            sender.OnValueChanged(sender.Value);
        }

        private static void OnCornerRadiusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = (DegreePresenter)d;
            var value  = (CornerRadius)e.NewValue;
            //
            // 设置所有元素
            foreach (Border item in sender.Children)
            {
                item.CornerRadius = value;
            }
        }

        private static void OnMaximumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = (DegreePresenter)d;
            
            //
            // 清空所有元素
            foreach (Border item in sender.Children)
            {
                //
                // 移除事件
                item.MouseLeftButtonDown -= sender.OnThumbMouseLeftButtonDown;
            }

            //
            //
            sender.Children.Clear();

            //
            // 2.重新创建元素
            // 3.重新设置元素
            sender.GenerateElement(sender.Maximum);
            sender.OnValueChanged(sender.Value);
        }

        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = (DegreePresenter)d;
            
            //
            //
            sender.OnValueChanged(sender.Value);
        }

        private static void OnIsLinearModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sender = (DegreePresenter)d;
            
            //
            //
            sender.OnValueChanged(sender.Value);
        }

        private void OnValueChanged(int value)
        {
            if (IsLinearMode)
            {
                OnLinearModeValueChanged(value);
            }
            else
            {
                OnDiscreteModeValueChanged(value);
            }


            //
            //
            SetCurrentValue(ValueProperty, value);
        }
        
        private void GenerateElement(int value)
        {
            value = Math.Clamp(value, 0, 32);
            
            //
            //
            var thumbWidth   = Math.Clamp(ThumbWidth, 4, 96);
            var thumbGap     = Math.Clamp(ThumbGap, 4, 96) / 2d;
            var margin = new Thickness(0, thumbGap, thumbGap * 2, thumbGap);
            var cornerRadius = CornerRadius;

            //
            //
            for (var i = 0; i < value; i++)
            {
                var border = new Border
                {
                    Background          = MediaFactory.ToSolidColorBrush(BrushKey.BackgroundLevel3),
                    CornerRadius        = cornerRadius,
                    Tag                 = i + 1,
                    UseLayoutRounding   = true,
                    SnapsToDevicePixels = true,
                    Height              = 12,
                    Width               = thumbWidth,
                    Margin              = margin,
                };

                border.MouseLeftButtonDown += OnThumbMouseLeftButtonDown;

                Children.Add(border);
            }

        }

        private void OnThumbMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var d = (Border)sender;
            var v = d.Tag is int tag ? tag : 1;

            //
            //
            OnValueChanged(v);
        }

        private static void HighlightElement(FrameworkElement element, Brush brush)
        {
            if (element is Border border)
            {
                border.Background = brush;
            }
        }

        private static void LowlightElement(FrameworkElement element)
        {
            if (element is Border border)
            {
                border.Background = MediaFactory.ToSolidColorBrush(BrushKey.BackgroundLevel1);
            }
        }

        private void OnLinearModeValueChanged(int value)
        {
            var brush = Brush;
            for (var i = 0; i < Children.Count; i++)
            {
                var index = i + 1;
                var item  = Children[i] as FrameworkElement;

                if (index <= value)
                {
                    HighlightElement(item,brush);
                }
                else
                {
                    LowlightElement(item);
                }
            }
        }

        private void OnDiscreteModeValueChanged(int value)
        {
            var brush = Brush;
            
            for (var i = 0; i < Children.Count; i++)
            {
                var index = i + 1;
                var item  = Children[i] as FrameworkElement;

                if (value == index)
                {
                    HighlightElement(item,brush);
                }
                else
                {
                    LowlightElement(item);
                }
            }
        }
        
        public Brush Brush
        {
            get => (Brush)GetValue(BrushProperty);
            set => SetValue(BrushProperty, value);
        }

        public bool IsLinearMode
        {
            get => (bool)GetValue(IsLinearModeProperty);
            set => SetValue(IsLinearModeProperty, Boxing.Box(value));
        }

        public CornerRadius CornerRadius
        {
            get => (CornerRadius)GetValue(CornerRadiusProperty);
            set => SetValue(CornerRadiusProperty, value);
        }
        
        public int ThumbHeight
        {
            get => (int)GetValue(ThumbHeightProperty);
            set => SetValue(ThumbHeightProperty, value);
        }

        public int ThumbWidth
        {
            get => (int)GetValue(ThumbWidthProperty);
            set => SetValue(ThumbWidthProperty, value);
        }

        public int ThumbGap
        {
            get => (int)GetValue(ThumbGapProperty);
            set => SetValue(ThumbGapProperty, value);
        }

        public int Maximum
        {
            get => (int)GetValue(MaximumProperty);
            set => SetValue(MaximumProperty, value);
        }
        
        public int Value
        {
            get => (int)GetValue(ValueProperty);
            set => SetValue(ValueProperty, value);
        }
    }
}